/*
*****************************************************************************
* COPYRIGHT AND WARRANTY INFORMATION
*
* Copyright 2002-2012, Advanced Audio Video Coding Standard, Part II
*
* DISCLAIMER OF WARRANTY
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
* License for the specific language governing rights and limitations under
* the License.
*
* THIS IS NOT A GRANT OF PATENT RIGHTS - SEE THE AVS PATENT POLICY.
* The AVS Working Group doesn't represent or warrant that the programs
* furnished here under are free of infringement of any third-party patents.
* Commercial implementations of AVS, including shareware, may be
* subject to royalty fees to patent holders. Information regarding
* the AVS patent policy for standardization procedure is available at
* AVS Web site http://www.avs.org.cn. Patent Licensing is outside
* of AVS Working Group.
*
* The Initial Developer of the Original Code is Video subgroup of AVS
* Workinggroup.
* Contributors: Qin Yu,         Zhichu He,  Weiran Li,    Yong Ling,
*               Zhenjiang Shao, Jie Chen,   Junjun Si,    Xiaozhen Zheng, 
*               Jian Lou,       Qiang Wang, Jianwen Chen, Haiwu Zhao,
*               Guoping Li,     Siwei Ma,   Junhao Zheng, Zhiming Wang
*               Li Zhang,
******************************************************************************
*/



/*
*************************************************************************************
* File name:
* Function:  Annex B Byte Stream format NAL Unit writing routines
*
*************************************************************************************
*/


#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>

#include "global.h"
#include "../../lcommon/inc/commonVariables.h"
#include "../../lcommon/inc/transform.h"
#include "bitstream.h"
#define MAXHEADERSIZE 100
#include "vlc.h"
#include "AEC.h"

#if FREQUENCY_WEIGHTING_QUANTIZATION
#include "wquant.h"
#endif


CopyRight CopyRights, *cp = &CopyRights;
CameraParamters CameraParameter, *camera = &CameraParameter;



////////////////////////////////////////////////////////////////////////////////
#ifdef SVA_START_CODE_EMULATION

unsigned char bit[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
OutputStream  ORABS;
OutputStream *pORABS = &ORABS;

void OpenORABS ( OutputStream *p, char *fname )
{
  p->f = fopen ( fname, "wb" );

  if ( p->f == NULL )
  {
    printf ( "\nCan't open file %s", fname );
    exit ( -1 );
  }

  p->uPreBytes      = 0xffffffff;
  p->iBytePosition    = 0;
  p->iBitOffset     = 0;
  p->iNumOfStuffBits    = 0;
  p->iBitsCount     = 0;
}
void CloseORABS ( OutputStream *p )
{
  if ( p->iBitOffset )
  {
    fwrite ( p->buf, 1, p->iBytePosition + 1, p->f );
  }
  else
  {
    fwrite ( p->buf, 1, p->iBytePosition  , p->f );
  }

  fclose ( p->f );
}
void FlushORABS ( OutputStream *p )
{
  fflush ( p->f );
}


int write_1_bit ( OutputStream *p, int b )
{
  int i;

  if ( p->iBytePosition == SVA_STREAM_BUF_SIZE )
  {
    i = fwrite ( p->buf, 1, SVA_STREAM_BUF_SIZE, p->f );

    if ( i != SVA_STREAM_BUF_SIZE )
    {
      printf ( "Fatal: write file error, exit (-1)\n" );
      exit ( -1 );
    }

    p->iBytePosition  = 0;
    p->iBitOffset   = 0;
  }

  p->uPreBytes <<= 1;

  if ( b )
  {
    p->buf[p->iBytePosition] |= bit[p->iBitOffset];
    p->uPreBytes |= 1;
  }
  else
  {
    p->buf[p->iBytePosition] &= ( ~bit[p->iBitOffset] );
  }

  p->iBitOffset++;

  if ( p->iBitOffset == 8 )
  {
    p->iBitOffset = 0;
    p->iBytePosition++;
  }

  p->iBitsCount++;
  return 0;
}
int write_n_bit ( OutputStream *p, int b, int n )
{

  if ( n > 30 )
  {
    return 1;
  }

  
  while ( n > 0 )
  { 
  write_1_bit ( p, b & ( 0x01 << ( n - 1 ) ) );
  n--;
  }

  return 0;
}


/*
*************************************************************************
* Function: one bit "1" is added to the end of stream, then some bits "0" are added to bytealigned position.
* Input:
* Output:
* Return:
* Attention:
* Author: Yulj 2004.07.16
*************************************************************************
*/
int write_align_stuff ( OutputStream *p )
{
  unsigned char c;
  int len;    //bit,rm52k_r2

  c = 0xff << ( 8 - p->iBitOffset );
  p->buf[p->iBytePosition] = ( c & p->buf[p->iBytePosition] ) | ( 0x80 >> ( p->iBitOffset ) );
  p->iBitsCount += 8 - p->iBitOffset;
  len   = 8 - p->iBitOffset;       //bit,rm52k_r2
  p->uPreBytes  = ( p->uPreBytes << ( 8 - p->iBitOffset ) ) & c;
  p->iNumOfStuffBits  += 8 - p->iBitOffset;
  p->iBitOffset = 0;
  p->iBytePosition++;
  return len;   //bit,rm52k_r2
}
//---end

int write_start_code ( OutputStream *p, unsigned char code )
{
  int i;

  if ( p->iBytePosition >= SVA_STREAM_BUF_SIZE - 4 && p->iBytePosition > 0 )
  {
    i = fwrite ( p->buf, 1, p->iBytePosition, p->f );

    if ( i != p->iBytePosition )
    {
      printf ( "\nWrite file error" );
      exit ( -1 );
    }
    p->iBytePosition  = 0;
    p->iBitOffset   = 0;
  }

  p->buf[p->iBytePosition  ] = 0;
  p->buf[p->iBytePosition + 1] = 0;
  p->buf[p->iBytePosition + 2] = 1;
  p->buf[p->iBytePosition + 3] = code;
  p->iBytePosition += 4;
  p->iBitsCount += 32;
  p->uPreBytes  = ( unsigned int ) code + 256;

  return 0;
}

/*
*************************************************************************
* Function:Open the output file for the bytestream
* Input: The filename of the file to be opened
* Output:
* Return: none.Function terminates the program in case of an error
* Attention:
*************************************************************************
*/


void OpenBitStreamFile ( char *Filename )
{
  OpenORABS ( pORABS, Filename );
}
void CloseBitStreamFile()
{
  CloseORABS ( pORABS );
}

/*
*************************************************************************
* Function:Write video edit code
* Input:
* Output:
* Return: 32bit for video edit code
* Attention:
*************************************************************************
*/

int WriteVideoEditCode()
{
  Bitstream *bitstream;
  unsigned char VideoEditCode[32];
  int  bitscount = 0;

  if ( ( bitstream = calloc ( 1, sizeof ( Bitstream ) ) ) == NULL )
  {
    no_mem_exit ( "Seuqence Header: bitstream" );
  }

  bitstream->streamBuffer = VideoEditCode;
  bitstream->bits_to_go = 8;

  bitscount = u_v ( 32, "video_edit_code", 0x1B7, bitstream );

  write_start_code ( pORABS, 0xb7 );

  free ( bitstream );

  return bitscount;
}



/*
*************************************************************************
* Function:Write sequence header information
* Input:
* Output:
* Return: sequence header length, including stuffing bits
* Attention:
*************************************************************************
*/

int WriteSequenceHeader()
{
  Bitstream *bitstream;
  unsigned char SequenceHeader[MAXHEADERSIZE];
  int  bitscount = 0;
  int  i, j, k;

#if (FREQUENCY_WEIGHTING_QUANTIZATION && COUNT_BIT_OVERHEAD)
  int bit_overhead;
  g_count_overhead_bit=0;
#endif


  if ( ( bitstream = calloc ( 1, sizeof ( Bitstream ) ) ) == NULL )
  {
    no_mem_exit ( "Seuqence Header: bitstream" );
  }

  bitstream->streamBuffer = SequenceHeader;
  bitstream->bits_to_go = 8;

  input->display_horizontal_size = img->width;
  input->display_vertical_size   = img->height;
  input->sample_precision = 1;

  input->aspect_ratio_information = 1;
  input->bit_rate_lower = 0;
  input->bit_rate_upper = 0;

  bitscount += u_v ( 32, "seqence start code", 0x1b0, bitstream );
  bitscount += u_v ( 8, "profile_id", input->profile_id, bitstream );
  bitscount += u_v ( 8, "level_id", input->level_id, bitstream );

#if MULTIVIEW_CODING
  bitscount += u_v ( 4, "view_number", input->view_number, bitstream );
  bitscount += u_v ( 1, "bUseDepth", input->bUseDepth, bitstream );
#endif

  bitscount += u_v ( 1, "progressive_sequence", input->progressive_sequence, bitstream );
#if INTERLACE_CODING
  bitscount += u_v ( 1, "field_coded_sequence", img->is_field_sequence, bitstream );
#endif

  bitscount += u_v ( 14, "horizontal_size", ( img->width - img->auto_crop_right ), bitstream );
  bitscount += u_v ( 14, "vertical_size", ( img->height - img->auto_crop_bottom ), bitstream );

  bitscount += u_v ( 2, "chroma format", input->chroma_format, bitstream );
#if EXTEND_BD
	if (input->profile_id == BASELINE10_PROFILE) // 10bit profile
	{
		bitscount += u_v ( 3, "sample precision", ((input->input_sample_bit_depth - 6) / 2), bitstream );
		bitscount += u_v ( 3, "encoding precision", ((input->sample_bit_depth - 6) / 2), bitstream );
	}
	else // other profile
	{
#endif
		bitscount += u_v ( 3, "sample precision", input->sample_precision, bitstream );
#if EXTEND_BD
	}
#endif
  bitscount += u_v ( 4, "aspect ratio information", input->aspect_ratio_information, bitstream );
  bitscount += u_v ( 4, "frame rate code", input->frame_rate_code, bitstream );

  bitscount += u_v ( 18, "bit rate lower", input->bit_rate_lower, bitstream );
  bitscount += u_v ( 1, "marker bit", 1, bitstream );
  bitscount += u_v ( 12, "bit rate upper", input->bit_rate_upper, bitstream );
  bitscount += u_v ( 1, "low delay", input->low_delay, bitstream );
  bitscount += u_v ( 1, "marker bit", 1, bitstream );

#if M3480_TEMPORAL_SCALABLE
  bitscount += u_v(1, "temporal_id exsit flag", temporal_id_exist_flag, bitstream);
#endif
  bitscount += u_v(18,"bbv buffer size",input->bbv_buffer_size,bitstream);
  bitscount += u_v ( 3, "Largest Coding Block Size", input->g_uiMaxSizeInBit, bitstream );

#if FREQUENCY_WEIGHTING_QUANTIZATION

#if COUNT_BIT_OVERHEAD
  bit_overhead=bitscount;
#endif

  bitscount += u_v ( 1, "weight_quant_enable", input->WQEnable, bitstream );
  if (input->WQEnable) {
	  bitscount += u_v ( 1, "load_seq_weight_quant_data_flag", input->SeqWQM, bitstream );
  }
  if(input->SeqWQM)
  {
	  int x,y,sizeId,uiWqMSize;
	  for (sizeId=0;sizeId<2;sizeId++)
	  {
		  uiWqMSize=min(1<<(sizeId+2),8);
	      for(y=0; y<uiWqMSize; y++)
		  {
		    for(x=0; x<uiWqMSize; x++)
		    {
			   bitscount += ue_v( "weight_quant_coeff", cur_wq_matrix[sizeId][y*uiWqMSize+x], bitstream );
		    }
		  }
	  }
  }


#if COUNT_BIT_OVERHEAD
  g_count_overhead_bit+=bitscount-bit_overhead;
#endif
#endif

#ifdef AVS2_S2_BGLONGTERM
#if AVS2_SCENE_CD
  bitscount+=u_v(1,"background_picture_disable",input->bg_enable^0x01,bitstream);
#else
  if( input->profile_id == 0x50 )
  {
    bitscount+=u_v(1,"background_picture_disable",input->bg_enable^0x01,bitstream);
  }
#endif

#endif


#if !D20141230_BUG_FIX
#if DMH
  bitscount += u_v ( 1, "dmh enabled", input->b_dmh_enabled, bitstream );
#endif
#endif 


#if MH_PSKIP_NEW
  bitscount += u_v (1, "mhpskip_enable", input->b_mhpskip_enabled, bitstream);
#endif

#if FFRAME
  bitscount += u_v ( 1, "dhp enabled", input->dhp_enabled, bitstream );
  bitscount += u_v ( 1, "wsm enabled", input->wsm_enabled, bitstream );
#endif

  bitscount += u_v ( 1,  "Asymmetric Motion Partitions", input->InterSearchAMP, bitstream );

  bitscount += u_v ( 1, "useNSQT", input->useNSQT, bitstream );

  bitscount += u_v ( 1, "useNSIP", input->useSDIP, bitstream );

#if SEC_TRANS
  bitscount += u_v ( 1, "secT enabled", input->b_secT_enabled, bitstream );
#endif

  bitscount += u_v ( 1,  "SAO Enable Flag", input->sao_enable, bitstream );
#if ALF
  bitscount += u_v ( 1,  "ALF Enable Flag", input->alf_enable, bitstream );
#endif

  bitscount += u_v ( 1, "pmvr enabled", input->b_pmvr_enabled, bitstream );
  
  bitscount += u_v(6, "num_of_RPS", gop_size_all, bitstream);
  for (i=0; i<gop_size_all; i++)
  {
	  bitscount += u_v( 1, "refered by others ", cfg_ref_all[i].referd_by_others, bitstream);
	  bitscount += u_v( 3, "num of reference picture", cfg_ref_all[i].num_of_ref, bitstream);

	  for ( j=0; j<cfg_ref_all[i].num_of_ref; j++)
	  {
#if REF_CD
		  bitscount += u_v( 6, "delta COI of ref pic", cfg_ref_all[i].ref_pic[j], bitstream );
#else
		  bitscount += u_v( 6, "delta COI of ref pic", cfg_ref_all[i].ref_pic[j]-1, bitstream );
#endif
	  }
	  bitscount += u_v( 3, "num of removed picture", cfg_ref_all[i].num_to_remove, bitstream);
	  for ( j=0; j<cfg_ref_all[i].num_to_remove; j++)
	  {
#if REF_CD
		  bitscount += u_v( 6, "delta COI of removed pic", cfg_ref_all[i].remove_pic[j], bitstream );
#else
		  bitscount += u_v( 6, "delta COI of removed pic", cfg_ref_all[i].remove_pic[j]-1, bitstream );
#endif
	  }
  }

#if PDD
  if (input->low_delay == 0)
  {
	  bitscount += u_v( 5, "picture_reorder_delay", picture_reorder_delay, bitstream );
  }	
#endif

#if XL_ADDED
  bitscount += u_v(1, "Cross Loop Filter Flag", input->crossSliceLoopFilter, bitstream);
#endif

  if ( input->profile_id == RESERVED_PROFILE_ID )
  {
    bitscount += u_v ( 1, "slice set flag", input->slice_set_enable ^ 0x01, bitstream ); //added by mz,2008.04
  }
  else
  {
    bitscount += u_v ( 3, "reserved bits", 0, bitstream );
  }

  k = bitscount >> 3;
  j = bitscount % 8;

  write_start_code ( pORABS, 0xb0 );

  for ( i = 4; i < k; i++ )
  {
    write_n_bit ( pORABS, SequenceHeader[i], 8 );
  }

  if ( j != 0 )
  {
    write_n_bit ( pORABS,/*SequenceHeader[k]*/bitstream->byte_buf, j );
  }

  bitscount += write_align_stuff ( pORABS ); //bit,rm52k_r2

  free ( bitstream );

  return bitscount;
}

int WriteSequenceEnd()
{
  write_start_code ( pORABS, 0xb1 );
  return 32;
}

/*
*************************************************************************
* Function:Write sequence display extension information
* Input:
* Output:
* Return: sequence display extension information lenght
* Attention:
*************************************************************************
*/


int WriteSequenceDisplayExtension()
{
  Bitstream *bitstream;
  unsigned char SequenceDisplayExtension[MAXHEADERSIZE];
  int  bitscount = 0;

  int  i, j, k;

  if ( ( bitstream = calloc ( 1, sizeof ( Bitstream ) ) ) == NULL )
  {
    no_mem_exit ( "Sequence Display Extension: bitstream" );
  }

  input->video_format = 1;
  input->video_range = 1;
  input->display_horizontal_size = 1920;
  input->display_vertical_size = 1280;

  bitstream->streamBuffer = SequenceDisplayExtension;
  bitstream->bits_to_go = 8;

  bitscount += u_v ( 32, "sequence display extension start code", 0x1b5, bitstream );
  bitscount += u_v ( 4, "extension id", 2, bitstream );
  bitscount += u_v ( 3, "video format", input->video_format, bitstream );
  bitscount += u_v ( 1, "video range", input->video_range, bitstream );
  bitscount += u_v ( 1, "color description", input->color_description, bitstream );

  if ( input->color_description )
  {
    bitscount += u_v ( 8, "color primaries", input->color_primaries, bitstream );
    bitscount += u_v ( 8, "transfer characteristics", input->transfer_characteristics, bitstream );
    bitscount += u_v ( 8, "matrix coefficients", input->matrix_coefficients, bitstream );
  }

  bitscount += u_v ( 14, "display horizontal size", input->display_horizontal_size, bitstream );
  //xyji 12.23
  bitscount += u_v ( 1, "marker bit", 1, bitstream );
  bitscount += u_v ( 14, "display vertical size", input->display_vertical_size, bitstream );
  //xyji 12.23
#if !M3472
  bitscount += u_v ( 2, "reserved bits", 0, bitstream );
#else
  bitscount += u_v ( 1, "3D mode", input->TD_mode, bitstream );
  
  if (input->TD_mode)
  {
    bitscount += u_v ( 8, "3D packing mode", input->view_packing_mode, bitstream );
    bitscount += u_v ( 1, "view reverse", input->view_reverse, bitstream );
  }
#endif

  k = bitscount >> 3;
  j = bitscount % 8;

  write_start_code ( pORABS, 0xb5 );

  for ( i = 4; i < k; i++ )
  {
    write_n_bit ( pORABS, SequenceDisplayExtension[i], 8 );
  }

  write_n_bit ( pORABS, SequenceDisplayExtension[k], j );
  bitscount += write_align_stuff ( pORABS );

  free ( bitstream );

  return bitscount;
}

/*
*************************************************************************
* Function:Write copyright extension information
* Input:
* Output:
* Return: copyright extension information lenght
* Attention:
*************************************************************************
*/
int WriteCopyrightExtension()
{
  Bitstream *bitstream;
  unsigned char CopyrightExtension[MAXHEADERSIZE];
  int  bitscount = 0;
  int  i, j, k;

  if ( ( bitstream = calloc ( 1, sizeof ( Bitstream ) ) ) == NULL )
  {
    no_mem_exit ( "Copyright Extension: bitstream" );
  }

  bitstream->streamBuffer = CopyrightExtension;
  bitstream->bits_to_go = 8;

  bitscount += u_v ( 32, "copyright extension start code", 0x1b5, bitstream );
  bitscount += u_v ( 4, "extension id", 4, bitstream );
  bitscount += u_v ( 1, "copyright flag", cp->copyright_flag, bitstream );
  bitscount += u_v ( 8, "copyright id", cp->copyright_id, bitstream );
  bitscount += u_v ( 1, "original or copy", cp->original_or_copy, bitstream );

  bitscount += u_v ( 7, "reserved_bits", 0, bitstream );
  bitscount += u_v ( 1, "marker bit", 1, bitstream );

  bitscount += u_v ( 20, "copyright number 1", cp->copyright_number, bitstream );
  bitscount += u_v ( 1, "marker bit", 1, bitstream );
  bitscount += u_v ( 22, "copyright number 2", cp->copyright_number, bitstream );
  bitscount += u_v ( 1, "marker bit", 1, bitstream );
  bitscount += u_v ( 22, "copyright number 3", cp->copyright_number, bitstream );

  k = bitscount >> 3;
  j = bitscount % 8;

  write_start_code ( pORABS, 0xb5 );

  for ( i = 4; i < k; i++ )
  {
    write_n_bit ( pORABS, CopyrightExtension[i], 8 );
  }

  write_n_bit ( pORABS, CopyrightExtension[k], j );
  bitscount += write_align_stuff ( pORABS );

  free ( bitstream );

  return bitscount;
}


/*
*************************************************************************
* Function:Write camera parameter extension information
* Input:
* Output:
* Return: camera parameter  extension information lenght
* Attention:
*************************************************************************
*/
int WriteCameraParametersExtension()
{
  Bitstream *bitstream;
  unsigned char CameraParametersExtension[MAXHEADERSIZE];
  int  bitscount = 0;
  int  i, j, k;

  if ( ( bitstream = calloc ( 1, sizeof ( Bitstream ) ) ) == NULL )
  {
    no_mem_exit ( "Camera Parameters Extension: bitstream" );
  }

  bitstream->streamBuffer = CameraParametersExtension;
  bitstream->bits_to_go = 8;

  bitscount += u_v ( 32, "camera parameters extension start code", 0x1b5, bitstream );
  bitscount += u_v ( 4, "extension id", 11, bitstream );
  bitscount += u_v ( 1, "reserved_bits", 0, bitstream );
  bitscount += u_v ( 7, "camera id", camera->camera_id, bitstream );
  bitscount += u_v ( 1, "marker bit", 1, bitstream );

  bitscount += u_v ( 22, "height_of_image_device", camera->height_of_image_device, bitstream );
  bitscount += u_v ( 1, "marker bit", 1, bitstream );

  bitscount += u_v ( 22, "focal_length", camera->focal_length, bitstream );
  bitscount += u_v ( 1, "marker bit", 1, bitstream );

  bitscount += u_v ( 22, "f_number", camera->f_number, bitstream );
  bitscount += u_v ( 1, "marker bit", 1, bitstream );

  bitscount += u_v ( 22, "vertical_angle_of_view", camera->vertical_angle_of_view, bitstream );
  bitscount += u_v ( 1, "marker bit", 1, bitstream );

  bitscount += u_v ( 16, "camera_position_x_upper", camera->camera_direction_x, bitstream );
  bitscount += u_v ( 1, "marker bit", 1, bitstream );
  bitscount += u_v ( 16, "camera_position_x_lower", camera->camera_direction_x, bitstream );
  bitscount += u_v ( 1, "marker bit", 1, bitstream );

  bitscount += u_v ( 16, "camera_position_y_upper", camera->camera_direction_y, bitstream );
  bitscount += u_v ( 1, "marker bit", 1, bitstream );

  bitscount += u_v ( 16, "camera_position_y_lower", camera->camera_direction_y, bitstream );
  bitscount += u_v ( 1, "marker bit", 1, bitstream );

  bitscount += u_v ( 16, "camera_position_z_upper", camera->camera_direction_z, bitstream );
  bitscount += u_v ( 1, "marker bit", 1, bitstream );
  bitscount += u_v ( 16, "camera_position_z_lower", camera->camera_direction_z, bitstream );
  bitscount += u_v ( 1, "marker bit", 1, bitstream );

  bitscount += u_v ( 22, "camera_direction_x", camera->camera_direction_x, bitstream );
  bitscount += u_v ( 1, "marker bit", 1, bitstream );

  bitscount += u_v ( 22, "camera_direction_y", camera->camera_direction_y, bitstream );
  bitscount += u_v ( 1, "marker bit", 1, bitstream );

  bitscount += u_v ( 22, "camera_direction_z", camera->camera_direction_z, bitstream );
  bitscount += u_v ( 1, "marker bit", 1, bitstream );

  bitscount += u_v ( 22, "image_plane_vertical_x", camera->image_plane_vertical_x, bitstream );
  bitscount += u_v ( 1, "marker bit", 1, bitstream );

  bitscount += u_v ( 22, "image_plane_vertical_y", camera->image_plane_vertical_y, bitstream );
  bitscount += u_v ( 1, "marker bit", 1, bitstream );

  bitscount += u_v ( 22, "image_plane_vertical_z", camera->image_plane_vertical_z, bitstream );
  bitscount += u_v ( 1, "marker bit", 1, bitstream );

  bitscount += u_v ( 32, "reserved_bits", 0, bitstream );

  k = bitscount >> 3;
  j = bitscount % 8;

  write_start_code ( pORABS, 0xb5 );

  for ( i = 4; i < k; i++ )
  {
    write_n_bit ( pORABS, CameraParametersExtension[i], 8 );
  }

  write_n_bit ( pORABS, CameraParametersExtension[k], j );
  bitscount += write_align_stuff ( pORABS );

  free ( bitstream );

  return bitscount;
}
#if M3480_TEMPORAL_SCALABLE
int WriteScalableExtension()
{
  Bitstream *bitstream;
  unsigned char TemporalScalableExtension[MAXHEADERSIZE];
  int  bitscount = 0;
  int  i, j, k;

  if ( ( bitstream = calloc ( 1, sizeof ( Bitstream ) ) ) == NULL )
  {
    no_mem_exit ( "Temporal Scalable Extension: bitstream" );
  }

  bitstream->streamBuffer = TemporalScalableExtension;
  bitstream->bits_to_go = 8;

  bitscount += u_v ( 32, "scalable extension start code", 0x1b5, bitstream );
  bitscount += u_v ( 4, "extension id", 3, bitstream );
  bitscount += u_v ( 3, "max temporal level", TEMPORAL_MAXLEVEL - 1, bitstream );
  
  for( i = 0; i < TEMPORAL_MAXLEVEL-1; i ++ )
  {
		bitscount += u_v ( 4, "fps code per temporal level", 1, bitstream );
		bitscount += u_v ( 18, "bit rate lower", 0, bitstream );
		bitscount += u_v ( 1, "marker bit", 1, bitstream );
		bitscount += u_v ( 12, "bit rate upper", 1, bitstream );
   }

  k = bitscount >> 3;
  j = bitscount % 8;

  write_start_code ( pORABS, 0xb5 );

  for ( i = 4; i < k; i++ )
  {
    write_n_bit ( pORABS, TemporalScalableExtension[i], 8 );
  }

  write_n_bit ( pORABS, TemporalScalableExtension[k], j );
  bitscount += write_align_stuff ( pORABS );

  free ( bitstream );

  return bitscount;
}
#endif

/*
*************************************************************************
* Function:Write user data
* Input:
* Output:
* Return: user data length
* Attention:
*************************************************************************
*/

int WriteUserData ( char *userdata )
{
  Bitstream *bitstream;
  unsigned char UserData[MAXHEADERSIZE];
  int  bitscount = 0;

  if ( ( bitstream = calloc ( 1, sizeof ( Bitstream ) ) ) == NULL )
  {
    no_mem_exit ( "User data: bitstream" );
  }

  bitstream->streamBuffer = UserData;
  bitstream->bits_to_go = 8;

  bitscount += u_v ( 32, "user data start code", 0x1b2, bitstream );
  write_start_code ( pORABS, 0xb2 );

  while ( *userdata )
  {
    write_n_bit ( pORABS, *userdata, 8 );
    bitscount += u_v ( 8, "user data", *userdata++, bitstream );
  }

  bitscount += write_align_stuff ( pORABS );
  free ( bitstream );

  return bitscount;
}

/*
*************************************************************************
* Function:Write bit steam to file
* Input:
* Output:
* Return: none
* Attention:
*************************************************************************
*/

void WriteBitstreamtoFile()
{
  int n, i;
  n = currBitStream->byte_pos;

  for ( i = 0; i < n; i++ )
  {
    if ( currBitStream->streamBuffer[i] == 0 && currBitStream->streamBuffer[i + 1] == 0 && currBitStream->streamBuffer[i + 2] == 1 )
    {
      write_start_code ( pORABS, currBitStream->streamBuffer[i + 3] );
      i = i + 4;
    }

    write_n_bit ( pORABS, currBitStream->streamBuffer[i], 8 );
  }

  if ( img->type == INTRA_IMG && img->number == 0 )
  {
    seq_header = stat->bit_use_header[3];
  }

  stat->bit_ctr += 8 * n;
  stat->bit_ctr += stat->bit_use_header[3];  //rm52k
  stat->bit_use_header[3] = 0;               //rm52k
}
#endif

/////////////////////////////////////////////////////////////////////////////////////////////
/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
void error ( char *text, int code )
{
  fprintf ( stderr, "%s\n", text );
  exit ( code );
}

/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
int start_sequence()
{
  int len = 0;
  char id_string[255] = "AVS test stream";

  if ( img->number == 0 )
  {
    OpenBitStreamFile ( input->outfile );
  }

  // Adaptive frequency weighting quantization
#if FREQUENCY_WEIGHTING_QUANTIZATION
  if(input->WQEnable)
  {
	  InitSeqQuantParam();
  }
#endif

  len = WriteSequenceHeader();

  if ( img->number == 0 )
  {
    len += WriteSequenceDisplayExtension();
    len += WriteCopyrightExtension();
    len += WriteCameraParametersExtension();
#if M3480_TEMPORAL_SCALABLE
	len += WriteScalableExtension();
#endif

    if ( strlen ( id_string ) > 1 )
    {
      len += WriteUserData ( id_string );
    }
  }

  return len;
}
/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:Mainly flushing of everything Add termination symbol, etc.
*************************************************************************
*/
int terminate_sequence()
{
  int len;
  len = WriteSequenceEnd();

  if ( img->EncodeEnd_flag == 1 )
  {
    CloseBitStreamFile();
  }

  printf ( "Sequence End\n" );
  return len;
}

